package com.luli.Utils;

import org.apache.commons.io.input.BOMInputStream;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class FileUtil {
    private static final int ROW_ACCESS_WINDOW_SIZE = 10000;
    private static Logger logger = LoggerFactory.getLogger(FileUtil.class);

    /**
     * 删除十五天前的文件
     *
     * @param path
     */
    public static void deleteFiles(String path) {
        deleteFiles(path, 15);
    }

    /**
     * 删除n天前的文件
     *
     * @param path
     * @param days
     */
    public static void deleteFiles(String path, int days) {
        File dir = new File(path);
        if (dir.exists()) {
            File[] lst = dir.listFiles();
            for (File f : lst) {
                if (System.currentTimeMillis() - f.lastModified() > 24 * 60 * 60 * 1000 * days) {
                    f.delete();
                }
            }
        }
    }

    /**
     * 删除目录下所有文件
     *
     * @param days
     */
    public static void deleteFilesAll(File dir, int... days) {
        if (days == null || days.length == 0) {
            if (dir.exists()) {
                File[] lst = dir.listFiles();
                for (File f : lst) {
                    deleteAll(f);
                }
            }
        } else {
            int day = days[0];
            if (dir.exists()) {
                File[] lst = dir.listFiles();
                for (File f : lst) {
                    if (System.currentTimeMillis() - f.lastModified() > 24 * 60 * 60 * 1000 * day) {
                        deleteAll(f);
                    }
                }
            }
        }
    }

    /**
     * 删除所有文件，包含本身
     *
     * @param file
     */
    public static void deleteAll(File file) {
        if (file.exists()) {
            if (file.isFile() || file.list().length == 0) {
                file.delete();
            } else {
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    deleteAll(files[i]);
                    files[i].delete();
                }
            }
            if (file.exists()) { // 如果文件本身就是目录 ，就要删除目录
                file.delete();
            }
        }
    }

    public static void createZipFile(File zipFile, File inputFile) {
        ZipOutputStream out = null;
        BufferedOutputStream bo = null;
        try {
            out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
            bo = new BufferedOutputStream(out);
            zip(out, inputFile, inputFile.getName(), bo);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bo.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void zip(ZipOutputStream out, File f, String base, BufferedOutputStream bo)
            throws Exception { // 方法重载
        if (f.isDirectory()) {
            File[] fl = f.listFiles();
            if (fl.length == 0) {
                out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base
            }
            for (int i = 0; i < fl.length; i++) {
                zip(out, fl[i], base + "/" + fl[i].getName(), bo); // 递归遍历子文件夹
            }
        } else {
            byte[] bufs = new byte[1024 * 10];
            out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base
            FileInputStream in = new FileInputStream(f);
            BufferedInputStream bi = new BufferedInputStream(in, 1024 * 10);
            int b = 0;
            while ((b = bi.read(bufs, 0, 1024 * 10)) != -1) {
                bo.write(bufs, 0, b); // 将字节流写入当前zip目录
            }
            bo.flush();
            bi.close();
            in.close();
        }
    }

    public static void output(final HttpServletResponse response, File file) {
        if (null == file) {
            return;
        }
        InputStream in = null;
        OutputStream out = null;
        try {
            response.reset();
            response.setHeader(
                    "content-disposition",
                    "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            in = new FileInputStream(file.getPath());
            int len = 0;
            byte[] buffer = new byte[1024];
            out = response.getOutputStream();
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            closeInputStream(in);
            closeOutputStream(out);
        }
    }

    public static void output(
            final HttpServletResponse response, final HttpServletRequest request, File file) {
        if (null == file) {
            return;
        }
        InputStream in = null;
        OutputStream out = null;
        try {
            response.reset();
            response.setHeader(
                    "content-disposition",
                    "attachment;filename=" + formatExportFileName(request, file.getName()));
            response.setHeader("Content-Length", String.valueOf(file.length()));
            in = new FileInputStream(file.getPath());
            logger.info(file.getPath());
            int len = 0;
            byte[] buffer = new byte[1024];
            out = response.getOutputStream();
            logger.info("in:"+in.toString());
            logger.info("out:"+out.toString());
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            out.flush();
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            throw new RuntimeException(e);
        } finally {
            closeInputStream(in);
            closeOutputStream(out);
        }
    }

    public static void outputExcel(
            final HttpServletResponse response, final HttpServletRequest request, File file) {
        if (null == file) {
            return;
        }
        InputStream in = null;
        OutputStream out = null;
        Workbook wb = null;
        SXSSFWorkbook sfwb = null;
        try {
            response.reset();
            response.setHeader(
                    "content-disposition",
                    "attachment;filename=" + formatExportFileName(request, file.getName()));
            response.setHeader("Content-Length", String.valueOf(file.length()));
            out = response.getOutputStream();
            wb = WorkbookFactory.create(new FileInputStream(file));
            if (wb instanceof XSSFWorkbook) {
                sfwb = new SXSSFWorkbook((XSSFWorkbook) wb, ROW_ACCESS_WINDOW_SIZE);
            }
            if (sfwb != null) {
                sfwb.write(out);
            } else {
                in = new FileInputStream(file.getPath());
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
            }
            out.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            closeInputStream(in);
            closeOutputStream(out);
        }
    }

    public static void closeOutputStream(OutputStream out) {
        if (out != null) {
            try {
                out.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    static void closeInputStream(InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 根据浏览器不同对文件名编码
     *
     * @param request
     * @param fileName
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String formatExportFileName(HttpServletRequest request, String fileName)
            throws UnsupportedEncodingException {
        String agent = request.getHeader("User-Agent");
        boolean isMSIE = (agent != null && agent.indexOf("MSIE") != -1);
        boolean isMSIE11 =
                (agent != null && agent.indexOf("Trident") != -1 && agent.indexOf("rv:11") != -1);
        if (isMSIE || isMSIE11) {
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
        }
        return fileName;
    }

    /**
     * 解决UTF8编码文件的BOM问题
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static BufferedReader getBufferedReader(String filePath) throws IOException {
        BOMInputStream bOMInputStream = new BOMInputStream(new FileInputStream(filePath));
        String bomCharset = bOMInputStream.getBOMCharsetName();
        String charsetName = bomCharset == null ? "UTF-8" : bomCharset;
        LineNumberReader reader =
                new LineNumberReader(
                        new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName));
        return reader;
    }

    /**
     * 解决UTF8编码文件的BOM问题
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static BufferedReader getBufferedReader(File file) throws IOException {
        BOMInputStream bOMInputStream = new BOMInputStream(new FileInputStream(file));
        String bomCharset = bOMInputStream.getBOMCharsetName();
        String charsetName = bomCharset == null ? "UTF-8" : bomCharset;
        LineNumberReader reader =
                new LineNumberReader(
                        new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName));
        return reader;
    }

    /**
     * 解决UTF8编码文件的BOM问题
     *
     * @param filePath
     * @return
     * @throws IOException
     */
    public static LineNumberReader getLineNumberReader(String filePath) throws IOException {
        BOMInputStream bOMInputStream = new BOMInputStream(new FileInputStream(filePath));
        String bomCharset = bOMInputStream.getBOMCharsetName();
        String charsetName = bomCharset == null ? "UTF-8" : bomCharset;
        LineNumberReader reader =
                new LineNumberReader(
                        new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName));
        return reader;
    }

    /**
     * 解决UTF8编码文件的BOM问题
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static LineNumberReader getLineNumberReader(File file) throws IOException {
        BOMInputStream bOMInputStream = new BOMInputStream(new FileInputStream(file));
        String bomCharset = bOMInputStream.getBOMCharsetName();
        String charsetName = bomCharset == null ? "UTF-8" : bomCharset;
        LineNumberReader reader =
                new LineNumberReader(
                        new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName));
        return reader;
    }

    /**
     * @desc 字节流输出文件
     * @date wxs 2019-03-01 14:05
     * @param file
     * @param data
     * @return void
     */
    public static void writeByteArrayToFile(File file, byte[] data) {
        FileOutputStream fos = null;
        BufferedInputStream bis = null;
        try {
            fos = new FileOutputStream(file);
            bis = new BufferedInputStream(new ByteArrayInputStream(data));
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                fos.write(buff, 0, bytesRead);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeOutputStream(fos);
            closeInputStream(bis);
        }
    }
}
